﻿
namespace Behemoth.SharePoint {

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Administration;
    using Microsoft.SharePoint.Utilities;
    using Behemoth.SharePoint.Logging;

    public static class ListItemExtensions {

        /// <summary>
        /// Safely gets the value of a list item field value.
        /// </summary>
        /// <param name="fieldInternalNameOrTitle">
        /// The field internal name or title for the desired field
        /// (internal name takes precedence, if found)</param>
        /// <typeparam name="T">The type of the desired object, see <ref="value"/></typeparam>
        /// <param name="item">SPListItem that contains the desired field value</param>
        /// <param name="value">
        /// For simple fields, this is usually something like string or int.
        /// For complex fields and custom field values, it may a subclass of SPField.
        /// </param>
        /// <returns>True for success and false for failure</returns>
        public static bool TryGetValue<T>(this SPListItem item, string fieldInternalNameOrTitle, out T value) {
            value = default(T);
            Guid fieldId = item.Fields.GetFieldId(fieldInternalNameOrTitle);
            return item.TryGetValue<T>(fieldId, fieldInternalNameOrTitle, out value);
        }
        /// <param name="fieldId">The field Id for the desired field</param>
        /// <typeparam name="T">The type of the desired object, see <ref="value"/></typeparam>
        /// <param name="item">SPListItem that contains the desired field value</param>
        /// <param name="value">
        /// For simple fields, this is usually something like string or int.
        /// For complex fields and custom field values, it may a subclass of SPField.
        /// </param>
        /// <returns>True for success and false for failure</returns>
        public static bool TryGetValue<T>(this SPListItem item, Guid fieldId, out T value) {
            return item.TryGetValue<T>(fieldId, string.Empty, out value);
        }

        private static bool TryGetValue<T>(this SPListItem item, Guid fieldId, string fieldTag, out T value) {
            value = default(T);
            try {
                if (fieldId == Guid.Empty)
                    return false;
                object rawValue = item[fieldId];
                if (rawValue != null) {
                    value = (T)rawValue;
                    return true;
                } else
                    return false;
            } catch (Exception ex) { // TODO narrow this down to a specific except if possible
                BehemothLoggingService.Default.Write(string.Format(
                    "Expected exception thrown trying to get SPListItem value for field '{0}' in list '{1}/{2}'. Exception: {3}",
                    string.IsNullOrEmpty(fieldTag) ? fieldId.ToString() : fieldTag,
                    item.ParentList.ParentWebUrl,
                    item.ParentList.Title,
                    ex.Message
                    ), TraceSeverity.Verbose, "Behemoth", "ListItemExtensions");
                //BehemothLoggingService.Default.Write(ex);
                return false;
            }
        }

        public static bool TryGetValueAsString(this SPListItem item, string fieldName, out string value) {
            value = null;
            SPField field = null;
            bool success = item.Fields.TryGetField(fieldName, out field);
            if (!success || field == null)
                return false;
            object fieldValue = null;
            if (!item.TryGetValue<object>(fieldName, out fieldValue))
                return false;
            try {
                value = field.GetFieldValueAsText(fieldValue);
                return true;
            } catch (System.Exception ex) { // TODO narrow this down to a specific except if possible
                BehemothLoggingService.Default.Write(string.Format(
                      "Expected exception thrown trying to get SPListItem value for field '{0}' in list '{1}/{2}'. Exception: {3}.",
                      fieldName,
                      item.ParentList.ParentWebUrl,
                      item.ParentList.Title,
                      ex.Message
                      ), TraceSeverity.Verbose, "Behemoth", "ListItemExtensions");
                //BehemothLoggingService.Default.Write(ex);
                return false;
            }
        }

        /// <summary>
        /// Updates a list item, with check-in and check-out if required.
        /// The caller is responsible for exception ahndling.
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static bool UpdateWithCheckOutAndIn(this SPListItem item) {
            if (item.ParentList.ForceCheckout && item.FileSystemObjectType.Equals(SPFileSystemObjectType.File)) {
                item.File.CheckOut();
                item.Update();
                item.File.CheckIn("Updated metadata programmatically."); // AppDomain.CurrentDomain.FriendlyName
            } else {
                item.Update();
            }
            return true;
        }

    } // class
} // namespace
